/*
  author Sylvain Bertrand <sylvain.bertrand@gmail.com>
  Protected by linux GNU GPLv2
  Copyright 2012-2014
*/
#include <linux/device.h>
#include <linux/i2c.h>

#include <alga/alga.h>
#include <uapi/alga/pixel_fmts.h>
#include <alga/timing.h>
#include <alga/dp.h>
#include <alga/amd/atombios/atb.h>
#include <alga/amd/atombios/dce.h>
#include <uapi/alga/amd/dce6/dce6.h>
#include <alga/amd/dce6/dce6_dev.h>

#include "dce6.h"

/* atb_dp_aux_native_write does not return the common -ATB_ERR but more */

long dpcd_wr(struct dce6 *dce, u8 i, u16 addr, u8 byte)
{
	long r;

	r = atb_dp_aux_native_write(dce->ddev.atb, dce->dps[i].atb_aux_i2c_id,
					dce->dps[i].hpd, addr, &byte, 1);
	if (r <= 0)
		return -DCE6_ERR;
	return 0;
}

long dpcd_lanes_vs_pre_emph_wr(struct dce6 *dce, u8 i, u8 vs_pre_emph)
{
	long r;
	u8 lanes_training_set[DP_MAX_LANES_N];

	memset(lanes_training_set, vs_pre_emph, dce->dps[i].lanes_n);

	r = atb_dp_aux_native_write(dce->ddev.atb, dce->dps[i].atb_aux_i2c_id,
		dce->dps[i].hpd, DPCD_TRAINING_LANE0_SET, lanes_training_set,
							dce->dps[i].lanes_n);
	if (r < dce->dps[i].lanes_n) {
		dev_err(dce->ddev.dev, "dce6:dp%u:link training: unable to "
			"dpcd write vs and pre emph for dp sink\n", i);
		return -DCE6_ERR;
	}
	return 0;
}

long dpcd_link_status(struct dce6 *dce, u8 i, u8 *link_status)
{
	long r;

	r = atb_dp_aux_native_read(dce->ddev.atb, dce->dps[i].atb_aux_i2c_id,
			dce->dps[i].hpd, DPCD_LANE0_1_STATUS, link_status,
							DPCD_LINK_STATUS_SZ);
	if (r < DPCD_LINK_STATUS_SZ) {
		dev_err(dce->ddev.dev, "dce6:dp%u:link training: unable to read"
							"link status\n", i);
		return -DCE6_ERR;
	}
	return 0;
}

long dpcd_info(struct dce6 * dce, u8 i)
{
	struct dp *dp;
	long r;

	dp = &dce->dps[i];

	memset(dp->dpcd_info, 0, sizeof(dp->dpcd_info));
	r = atb_dp_aux_native_read(dce->ddev.atb, dp->atb_aux_i2c_id, dp->hpd,
				DPCD_REV, dp->dpcd_info, sizeof(dp->dpcd_info));
	if (r <= 0)
		return -DCE6_ERR;

	dev_info(dce->ddev.dev,
"dce6:dp%u dpcd=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
							i, dp->dpcd_info[0],
							dp->dpcd_info[1],
							dp->dpcd_info[2],
							dp->dpcd_info[3],
							dp->dpcd_info[4],
							dp->dpcd_info[5],
							dp->dpcd_info[6],
							dp->dpcd_info[7]);
	return 0;
}
